home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / p_weapon.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  36.2 KB  |  1,466 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // g_weapon.c
  21.  
  22. #include "g_local.h"
  23. #include "m_player.h"
  24.  
  25.  
  26. static qboolean    is_quad;
  27. static byte        is_silenced;
  28.  
  29.  
  30. void weapon_grenade_fire (edict_t *ent, qboolean held);
  31.  
  32.  
  33. void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
  34. {
  35.     vec3_t    _distance;
  36.  
  37.     VectorCopy (distance, _distance);
  38.     if (client->pers.hand == LEFT_HANDED)
  39.         _distance[1] *= -1;
  40.     else if (client->pers.hand == CENTER_HANDED)
  41.         _distance[1] = 0;
  42.     G_ProjectSource (point, _distance, forward, right, result);
  43. }
  44.  
  45.  
  46. /*
  47. ===============
  48. PlayerNoise
  49.  
  50. Each player can have two noise objects associated with it:
  51. a personal noise (jumping, pain, weapon firing), and a weapon
  52. target noise (bullet wall impacts)
  53.  
  54. Monsters that don't directly see the player can move
  55. to a noise in hopes of seeing the player from there.
  56. ===============
  57. */
  58. void PlayerNoise(edict_t *who, vec3_t where, int type)
  59. {
  60.     edict_t        *noise;
  61.  
  62.     if (type == PNOISE_WEAPON)
  63.     {
  64.         if (who->client->silencer_shots)
  65.         {
  66.             who->client->silencer_shots--;
  67.             return;
  68.         }
  69.     }
  70.  
  71.     if (deathmatch->value)
  72.         return;
  73.  
  74.     if (who->flags & FL_NOTARGET)
  75.         return;
  76.  
  77.  
  78.     if (!who->mynoise)
  79.     {
  80.         noise = G_Spawn();
  81.         noise->classname = "player_noise";
  82.         VectorSet (noise->mins, -8, -8, -8);
  83.         VectorSet (noise->maxs, 8, 8, 8);
  84.         noise->owner = who;
  85.         noise->svflags = SVF_NOCLIENT;
  86.         who->mynoise = noise;
  87.  
  88.         noise = G_Spawn();
  89.         noise->classname = "player_noise";
  90.         VectorSet (noise->mins, -8, -8, -8);
  91.         VectorSet (noise->maxs, 8, 8, 8);
  92.         noise->owner = who;
  93.         noise->svflags = SVF_NOCLIENT;
  94.         who->mynoise2 = noise;
  95.     }
  96.  
  97.     if (type == PNOISE_SELF || type == PNOISE_WEAPON)
  98.     {
  99.         noise = who->mynoise;
  100.         level.sound_entity = noise;
  101.         level.sound_entity_framenum = level.framenum;
  102.     }
  103.     else // type == PNOISE_IMPACT
  104.     {
  105.         noise = who->mynoise2;
  106.         level.sound2_entity = noise;
  107.         level.sound2_entity_framenum = level.framenum;
  108.     }
  109.  
  110.     VectorCopy (where, noise->s.origin);
  111.     VectorSubtract (where, noise->maxs, noise->absmin);
  112.     VectorAdd (where, noise->maxs, noise->absmax);
  113.     noise->teleport_time = level.time;
  114.     gi.linkentity (noise);
  115. }
  116.  
  117.  
  118. qboolean Pickup_Weapon (edict_t *ent, edict_t *other)
  119. {
  120.     int            index;
  121.     gitem_t        *ammo;
  122.  
  123.     index = ITEM_INDEX(ent->item);
  124.  
  125.     if ( ( ((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value) 
  126.         && other->client->pers.inventory[index])
  127.     {
  128.         if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM) ) )
  129.             return false;    // leave the weapon for others to pickup
  130.     }
  131.  
  132.     other->client->pers.inventory[index]++;
  133.  
  134.     if (!(ent->spawnflags & DROPPED_ITEM) )
  135.     {
  136.         // give them some ammo with it
  137.         ammo = FindItem (ent->item->ammo);
  138.         if ( (int)dmflags->value & DF_INFINITE_AMMO )
  139.             Add_Ammo (other, ammo, 1000);
  140.         else
  141.             Add_Ammo (other, ammo, ammo->quantity);
  142.  
  143.         if (! (ent->spawnflags & DROPPED_PLAYER_ITEM) )
  144.         {
  145.             if (deathmatch->value)
  146.             {
  147.                 if ((int)(dmflags->value) & DF_WEAPONS_STAY)
  148.                     ent->flags |= FL_RESPAWN;
  149.                 else
  150.                     SetRespawn (ent, 30);
  151.             }
  152.             if (coop->value)
  153.                 ent->flags |= FL_RESPAWN;
  154.         }
  155.     }
  156.  
  157.     if (other->client->pers.weapon != ent->item && 
  158.         (other->client->pers.inventory[index] == 1) &&
  159.         ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
  160.         other->client->newweapon = ent->item;
  161.  
  162.     return true;
  163. }
  164.  
  165.  
  166. /*
  167. ===============
  168. ChangeWeapon
  169.  
  170. The old weapon has been dropped all the way, so make the new one
  171. current
  172. ===============
  173. */
  174. void ChangeWeapon (edict_t *ent)
  175. {
  176.     int i;
  177.  
  178.     if (ent->client->grenade_time)
  179.     {
  180.         ent->client->grenade_time = level.time;
  181.         ent->client->weapon_sound = 0;
  182.         weapon_grenade_fire (ent, false);
  183.         ent->client->grenade_time = 0;
  184.     }
  185.  
  186.     ent->client->pers.lastweapon = ent->client->pers.weapon;
  187.     ent->client->pers.weapon = ent->client->newweapon;
  188.     ent->client->newweapon = NULL;
  189.     ent->client->machinegun_shots = 0;
  190.  
  191.     // set visible model
  192.     if (ent->s.modelindex == 255) {
  193.         if (ent->client->pers.weapon)
  194.             i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8);
  195.         else
  196.             i = 0;
  197.         ent->s.skinnum = (ent - g_edicts - 1) | i;
  198.     }
  199.  
  200.     if (ent->client->pers.weapon && ent->client->pers.weapon->ammo)
  201.         ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo));
  202.     else
  203.         ent->client->ammo_index = 0;
  204.  
  205.     if (!ent->client->pers.weapon)
  206.     {    // dead
  207.         ent->client->ps.gunindex = 0;
  208.         return;
  209.     }
  210.  
  211.     ent->client->weaponstate = WEAPON_ACTIVATING;
  212.     ent->client->ps.gunframe = 0;
  213.     ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
  214.  
  215.     ent->client->anim_priority = ANIM_PAIN;
  216.     if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  217.     {
  218.             ent->s.frame = FRAME_crpain1;
  219.             ent->client->anim_end = FRAME_crpain4;
  220.     }
  221.     else
  222.     {
  223.             ent->s.frame = FRAME_pain301;
  224.             ent->client->anim_end = FRAME_pain304;
  225.             
  226.     }
  227. }
  228.  
  229. /*
  230. =================
  231. NoAmmoWeaponChange
  232. =================
  233. */
  234. void NoAmmoWeaponChange (edict_t *ent)
  235. {
  236.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("slugs"))]
  237.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("railgun"))] )
  238.     {
  239.         ent->client->newweapon = FindItem ("railgun");
  240.         return;
  241.     }
  242.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]
  243.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("hyperblaster"))] )
  244.     {
  245.         ent->client->newweapon = FindItem ("hyperblaster");
  246.         return;
  247.     }
  248.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  249.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("chaingun"))] )
  250.     {
  251.         ent->client->newweapon = FindItem ("chaingun");
  252.         return;
  253.     }
  254.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("bullets"))]
  255.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("machinegun"))] )
  256.     {
  257.         ent->client->newweapon = FindItem ("machinegun");
  258.         return;
  259.     }
  260.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))] > 1
  261.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("super shotgun"))] )
  262.     {
  263.         ent->client->newweapon = FindItem ("super shotgun");
  264.         return;
  265.     }
  266.     if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("shells"))]
  267.         &&  ent->client->pers.inventory[ITEM_INDEX(FindItem("shotgun"))] )
  268.     {
  269.         ent->client->newweapon = FindItem ("shotgun");
  270.         return;
  271.     }
  272.     ent->client->newweapon = FindItem ("blaster");
  273. }
  274.  
  275. /*
  276. =================
  277. Think_Weapon
  278.  
  279. Called by ClientBeginServerFrame and ClientThink
  280. =================
  281. */
  282. void Think_Weapon (edict_t *ent)
  283. {
  284.     // if just died, put the weapon away
  285.     if (ent->health < 1)
  286.     {
  287.         ent->client->newweapon = NULL;
  288.         ChangeWeapon (ent);
  289.     }
  290.  
  291.     // call active weapon think routine
  292.     if (ent->client->pers.weapon && ent->client->pers.weapon->weaponthink)
  293.     {
  294.         is_quad = (ent->client->quad_framenum > level.framenum);
  295.         if (ent->client->silencer_shots)
  296.             is_silenced = MZ_SILENCED;
  297.         else
  298.             is_silenced = 0;
  299.         ent->client->pers.weapon->weaponthink (ent);
  300.     }
  301. }
  302.  
  303.  
  304. /*
  305. ================
  306. Use_Weapon
  307.  
  308. Make the weapon ready if there is ammo
  309. ================
  310. */
  311. void Use_Weapon (edict_t *ent, gitem_t *item)
  312. {
  313.     int            ammo_index;
  314.     gitem_t        *ammo_item;
  315.  
  316.     // see if we're already using it
  317.     if (item == ent->client->pers.weapon)
  318.         return;
  319.  
  320.     if (item->ammo && !g_select_empty->value && !(item->flags & IT_AMMO))
  321.     {
  322.         ammo_item = FindItem(item->ammo);
  323.         ammo_index = ITEM_INDEX(ammo_item);
  324.  
  325.         if (!ent->client->pers.inventory[ammo_index])
  326.         {
  327.             gi.cprintf (ent, PRINT_HIGH, "No %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  328.             return;
  329.         }
  330.  
  331.         if (ent->client->pers.inventory[ammo_index] < item->quantity)
  332.         {
  333.             gi.cprintf (ent, PRINT_HIGH, "Not enough %s for %s.\n", ammo_item->pickup_name, item->pickup_name);
  334.             return;
  335.         }
  336.     }
  337.  
  338.     // change to this weapon when down
  339.     ent->client->newweapon = item;
  340. }
  341.  
  342.  
  343.  
  344. /*
  345. ================
  346. Drop_Weapon
  347. ================
  348. */
  349. void Drop_Weapon (edict_t *ent, gitem_t *item)
  350. {
  351.     int        index;
  352.  
  353.     if ((int)(dmflags->value) & DF_WEAPONS_STAY)
  354.         return;
  355.  
  356.     index = ITEM_INDEX(item);
  357.     // see if we're already using it
  358.     if ( ((item == ent->client->pers.weapon) || (item == ent->client->newweapon))&& (ent->client->pers.inventory[index] == 1) )
  359.     {
  360.         gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
  361.         return;
  362.     }
  363.  
  364.     Drop_Item (ent, item);
  365.     ent->client->pers.inventory[index]--;
  366. }
  367.  
  368.  
  369. /*
  370. ================
  371. Weapon_Generic
  372.  
  373. A generic function to handle the basics of weapon thinking
  374. ================
  375. */
  376. #define FRAME_FIRE_FIRST        (FRAME_ACTIVATE_LAST + 1)
  377. #define FRAME_IDLE_FIRST        (FRAME_FIRE_LAST + 1)
  378. #define FRAME_DEACTIVATE_FIRST    (FRAME_IDLE_LAST + 1)
  379.  
  380. static void Weapon_Generic2 (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
  381. {
  382.     int        n;
  383.  
  384.     if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
  385.     {
  386.         return;
  387.     }
  388.  
  389.     if (ent->client->weaponstate == WEAPON_DROPPING)
  390.     {
  391.         if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
  392.         {
  393.             ChangeWeapon (ent);
  394.             return;
  395.         }
  396.         else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
  397.         {
  398.             ent->client->anim_priority = ANIM_REVERSE;
  399.             if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  400.             {
  401.                 ent->s.frame = FRAME_crpain4+1;
  402.                 ent->client->anim_end = FRAME_crpain1;
  403.             }
  404.             else
  405.             {
  406.                 ent->s.frame = FRAME_pain304+1;
  407.                 ent->client->anim_end = FRAME_pain301;
  408.                 
  409.             }
  410.         }
  411.  
  412.         ent->client->ps.gunframe++;
  413.         return;
  414.     }
  415.  
  416.     if (ent->client->weaponstate == WEAPON_ACTIVATING)
  417.     {
  418.         if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST || instantweap->value)
  419.         {
  420.             ent->client->weaponstate = WEAPON_READY;
  421.             ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  422.             return;
  423.         }
  424.  
  425.         ent->client->ps.gunframe++;
  426.         return;
  427.     }
  428.  
  429.     if ((ent->client->newweapon) && (ent->client->weaponstate != WEAPON_FIRING))
  430.     {
  431.         ent->client->weaponstate = WEAPON_DROPPING;
  432.         if (instantweap->value) {
  433.             ChangeWeapon(ent);
  434.             return;
  435.         } else
  436.             ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
  437.  
  438.         if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
  439.         {
  440.             ent->client->anim_priority = ANIM_REVERSE;
  441.             if(ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  442.             {
  443.                 ent->s.frame = FRAME_crpain4+1;
  444.                 ent->client->anim_end = FRAME_crpain1;
  445.             }
  446.             else
  447.             {
  448.                 ent->s.frame = FRAME_pain304+1;
  449.                 ent->client->anim_end = FRAME_pain301;
  450.                 
  451.             }
  452.         }
  453.         return;
  454.     }
  455.  
  456.     if (ent->client->weaponstate == WEAPON_READY)
  457.     {
  458.         if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  459.         {
  460.             ent->client->latched_buttons &= ~BUTTON_ATTACK;
  461.             if ((!ent->client->ammo_index) || 
  462.                 ( ent->client->pers.inventory[ent->client->ammo_index] >= ent->client->pers.weapon->quantity))
  463.             {
  464.                 ent->client->ps.gunframe = FRAME_FIRE_FIRST;
  465.                 ent->client->weaponstate = WEAPON_FIRING;
  466.  
  467.                 // start the animation
  468.                 ent->client->anim_priority = ANIM_ATTACK;
  469.                 if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  470.                 {
  471.                     ent->s.frame = FRAME_crattak1-1;
  472.                     ent->client->anim_end = FRAME_crattak9;
  473.                 }
  474.                 else
  475.                 {
  476.                     ent->s.frame = FRAME_attack1-1;
  477.                     ent->client->anim_end = FRAME_attack8;
  478.                 }
  479.             }
  480.             else
  481.             {
  482.                 if (level.time >= ent->pain_debounce_time)
  483.                 {
  484.                     gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  485.                     ent->pain_debounce_time = level.time + 1;
  486.                 }
  487.                 NoAmmoWeaponChange (ent);
  488.             }
  489.         }
  490.         else
  491.         {
  492.             if (ent->client->ps.gunframe == FRAME_IDLE_LAST)
  493.             {
  494.                 ent->client->ps.gunframe = FRAME_IDLE_FIRST;
  495.                 return;
  496.             }
  497.  
  498.             if (pause_frames)
  499.             {
  500.                 for (n = 0; pause_frames[n]; n++)
  501.                 {
  502.                     if (ent->client->ps.gunframe == pause_frames[n])
  503.                     {
  504.                         if (rand()&15)
  505.                             return;
  506.                     }
  507.                 }
  508.             }
  509.  
  510.             ent->client->ps.gunframe++;
  511.             return;
  512.         }
  513.     }
  514.  
  515.     if (ent->client->weaponstate == WEAPON_FIRING)
  516.     {
  517.         for (n = 0; fire_frames[n]; n++)
  518.         {
  519.             if (ent->client->ps.gunframe == fire_frames[n])
  520.             {
  521. //ZOID
  522.                 if (!CTFApplyStrengthSound(ent))
  523. //ZOID
  524.                 if (ent->client->quad_framenum > level.framenum)
  525.                     gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage3.wav"), 1, ATTN_NORM, 0);
  526. //ZOID
  527.                 CTFApplyHasteSound(ent);
  528. //ZOID
  529.  
  530.                 fire (ent);
  531.                 break;
  532.             }
  533.         }
  534.  
  535.         if (!fire_frames[n])
  536.             ent->client->ps.gunframe++;
  537.  
  538.         if (ent->client->ps.gunframe == FRAME_IDLE_FIRST+1)
  539.             ent->client->weaponstate = WEAPON_READY;
  540.     }
  541. }
  542.  
  543. //ZOID
  544. void Weapon_Generic (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
  545. {
  546.     int oldstate = ent->client->weaponstate;
  547.  
  548.     Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, 
  549.         FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, 
  550.         fire_frames, fire);
  551.  
  552.     // run the weapon frame again if hasted
  553.     if (stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
  554.         ent->client->weaponstate == WEAPON_FIRING)
  555.         return;
  556.  
  557.     if ((CTFApplyHaste(ent) ||
  558.         (Q_stricmp(ent->client->pers.weapon->pickup_name, "Grapple") == 0 &&
  559.         ent->client->weaponstate != WEAPON_FIRING))
  560.         && oldstate == ent->client->weaponstate) {
  561.         Weapon_Generic2 (ent, FRAME_ACTIVATE_LAST, FRAME_FIRE_LAST, 
  562.             FRAME_IDLE_LAST, FRAME_DEACTIVATE_LAST, pause_frames, 
  563.             fire_frames, fire);
  564.     }
  565. }
  566. //ZOID
  567.  
  568. /*
  569. ======================================================================
  570.  
  571. GRENADE
  572.  
  573. ======================================================================
  574. */
  575.  
  576. #define GRENADE_TIMER        3.0
  577. #define GRENADE_MINSPEED    400
  578. #define GRENADE_MAXSPEED    800
  579.  
  580. void weapon_grenade_fire (edict_t *ent, qboolean held)
  581. {
  582.     vec3_t    offset;
  583.     vec3_t    forward, right;
  584.     vec3_t    start;
  585.     int        damage = 125;
  586.     float    timer;
  587.     int        speed;
  588.     float    radius;
  589.  
  590.     radius = damage+40;
  591.     if (is_quad)
  592.         damage *= 4;
  593.  
  594.     VectorSet(offset, 8, 8, ent->viewheight-8);
  595.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  596.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  597.  
  598.     timer = ent->client->grenade_time - level.time;
  599.     speed = GRENADE_MINSPEED + (GRENADE_TIMER - timer) * ((GRENADE_MAXSPEED - GRENADE_MINSPEED) / GRENADE_TIMER);
  600.     fire_grenade2 (ent, start, forward, damage, speed, timer, radius, held);
  601.  
  602.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  603.         ent->client->pers.inventory[ent->client->ammo_index]--;
  604.  
  605.     ent->client->grenade_time = level.time + 1.0;
  606.  
  607.     if(ent->deadflag || ent->s.modelindex != 255) // VWep animations screw up corpses
  608.     {
  609.         return;
  610.     }
  611.  
  612.     if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  613.     {
  614.         ent->client->anim_priority = ANIM_ATTACK;
  615.         ent->s.frame = FRAME_crattak1-1;
  616.         ent->client->anim_end = FRAME_crattak3;
  617.     }
  618.     else
  619.     {
  620.         ent->client->anim_priority = ANIM_REVERSE;
  621.         ent->s.frame = FRAME_wave08;
  622.         ent->client->anim_end = FRAME_wave01;
  623.     }
  624. }
  625.  
  626. void Weapon_Grenade (edict_t *ent)
  627. {
  628.     if ((ent->client->newweapon) && (ent->client->weaponstate == WEAPON_READY))
  629.     {
  630.         ChangeWeapon (ent);
  631.         return;
  632.     }
  633.  
  634.     if (ent->client->weaponstate == WEAPON_ACTIVATING)
  635.     {
  636.         ent->client->weaponstate = WEAPON_READY;
  637.         ent->client->ps.gunframe = 16;
  638.         return;
  639.     }
  640.  
  641.     if (ent->client->weaponstate == WEAPON_READY)
  642.     {
  643.         if ( ((ent->client->latched_buttons|ent->client->buttons) & BUTTON_ATTACK) )
  644.         {
  645.             ent->client->latched_buttons &= ~BUTTON_ATTACK;
  646.             if (ent->client->pers.inventory[ent->client->ammo_index])
  647.             {
  648.                 ent->client->ps.gunframe = 1;
  649.                 ent->client->weaponstate = WEAPON_FIRING;
  650.                 ent->client->grenade_time = 0;
  651.             }
  652.             else
  653.             {
  654.                 if (level.time >= ent->pain_debounce_time)
  655.                 {
  656.                     gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  657.                     ent->pain_debounce_time = level.time + 1;
  658.                 }
  659.                 NoAmmoWeaponChange (ent);
  660.             }
  661.             return;
  662.         }
  663.  
  664.         if ((ent->client->ps.gunframe == 29) || (ent->client->ps.gunframe == 34) || (ent->client->ps.gunframe == 39) || (ent->client->ps.gunframe == 48))
  665.         {
  666.             if (rand()&15)
  667.                 return;
  668.         }
  669.  
  670.         if (++ent->client->ps.gunframe > 48)
  671.             ent->client->ps.gunframe = 16;
  672.         return;
  673.     }
  674.  
  675.     if (ent->client->weaponstate == WEAPON_FIRING)
  676.     {
  677.         if (ent->client->ps.gunframe == 5)
  678.             gi.sound(ent, CHAN_WEAPON, gi.soundindex("weapons/hgrena1b.wav"), 1, ATTN_NORM, 0);
  679.  
  680.         if (ent->client->ps.gunframe == 11)
  681.         {
  682.             if (!ent->client->grenade_time)
  683.             {
  684.                 ent->client->grenade_time = level.time + GRENADE_TIMER + 0.2;
  685.                 ent->client->weapon_sound = gi.soundindex("weapons/hgrenc1b.wav");
  686.             }
  687.  
  688.             // they waited too long, detonate it in their hand
  689.             if (!ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
  690.             {
  691.                 ent->client->weapon_sound = 0;
  692.                 weapon_grenade_fire (ent, true);
  693.                 ent->client->grenade_blew_up = true;
  694.             }
  695.  
  696.             if (ent->client->buttons & BUTTON_ATTACK)
  697.                 return;
  698.  
  699.             if (ent->client->grenade_blew_up)
  700.             {
  701.                 if (level.time >= ent->client->grenade_time)
  702.                 {
  703.                     ent->client->ps.gunframe = 15;
  704.                     ent->client->grenade_blew_up = false;
  705.                 }
  706.                 else
  707.                 {
  708.                     return;
  709.                 }
  710.             }
  711.         }
  712.  
  713.         if (ent->client->ps.gunframe == 12)
  714.         {
  715.             ent->client->weapon_sound = 0;
  716.             weapon_grenade_fire (ent, false);
  717.         }
  718.  
  719.         if ((ent->client->ps.gunframe == 15) && (level.time < ent->client->grenade_time))
  720.             return;
  721.  
  722.         ent->client->ps.gunframe++;
  723.  
  724.         if (ent->client->ps.gunframe == 16)
  725.         {
  726.             ent->client->grenade_time = 0;
  727.             ent->client->weaponstate = WEAPON_READY;
  728.         }
  729.     }
  730. }
  731.  
  732. /*
  733. ======================================================================
  734.  
  735. GRENADE LAUNCHER
  736.  
  737. ======================================================================
  738. */
  739.  
  740. void weapon_grenadelauncher_fire (edict_t *ent)
  741. {
  742.     vec3_t    offset;
  743.     vec3_t    forward, right;
  744.     vec3_t    start;
  745.     int        damage = 120;
  746.     float    radius;
  747.  
  748.     radius = damage+40;
  749.     if (is_quad)
  750.         damage *= 4;
  751.  
  752.     VectorSet(offset, 8, 8, ent->viewheight-8);
  753.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  754.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  755.  
  756.     VectorScale (forward, -2, ent->client->kick_origin);
  757.     ent->client->kick_angles[0] = -1;
  758.  
  759.     fire_grenade (ent, start, forward, damage, 600, 2.5, radius);
  760.  
  761.     gi.WriteByte (svc_muzzleflash);
  762.     gi.WriteShort (ent-g_edicts);
  763.     gi.WriteByte (MZ_GRENADE | is_silenced);
  764.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  765.  
  766.     ent->client->ps.gunframe++;
  767.  
  768.     PlayerNoise(ent, start, PNOISE_WEAPON);
  769.  
  770.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  771.         ent->client->pers.inventory[ent->client->ammo_index]--;
  772. }
  773.  
  774. void Weapon_GrenadeLauncher (edict_t *ent)
  775. {
  776.     static int    pause_frames[]    = {34, 51, 59, 0};
  777.     static int    fire_frames[]    = {6, 0};
  778.  
  779.     Weapon_Generic (ent, 5, 16, 59, 64, pause_frames, fire_frames, weapon_grenadelauncher_fire);
  780. }
  781.  
  782. /*
  783. ======================================================================
  784.  
  785. ROCKET
  786.  
  787. ======================================================================
  788. */
  789.  
  790. void Weapon_RocketLauncher_Fire (edict_t *ent)
  791. {
  792.     vec3_t    offset, start;
  793.     vec3_t    forward, right;
  794.     int        damage;
  795.     float    damage_radius;
  796.     int        radius_damage;
  797.  
  798.     damage = 100 + (int)(random() * 20.0);
  799.     radius_damage = 120;
  800.     damage_radius = 120;
  801.     if (is_quad)
  802.     {
  803.         damage *= 4;
  804.         radius_damage *= 4;
  805.     }
  806.  
  807.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  808.  
  809.     VectorScale (forward, -2, ent->client->kick_origin);
  810.     ent->client->kick_angles[0] = -1;
  811.  
  812.     VectorSet(offset, 8, 8, ent->viewheight-8);
  813.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  814.     fire_rocket (ent, start, forward, damage, 650, damage_radius, radius_damage);
  815.  
  816.     // send muzzle flash
  817.     gi.WriteByte (svc_muzzleflash);
  818.     gi.WriteShort (ent-g_edicts);
  819.     gi.WriteByte (MZ_ROCKET | is_silenced);
  820.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  821.  
  822.     ent->client->ps.gunframe++;
  823.  
  824.     PlayerNoise(ent, start, PNOISE_WEAPON);
  825.  
  826.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  827.         ent->client->pers.inventory[ent->client->ammo_index]--;
  828. }
  829.  
  830. void Weapon_RocketLauncher (edict_t *ent)
  831. {
  832.     static int    pause_frames[]    = {25, 33, 42, 50, 0};
  833.     static int    fire_frames[]    = {5, 0};
  834.  
  835.     Weapon_Generic (ent, 4, 12, 50, 54, pause_frames, fire_frames, Weapon_RocketLauncher_Fire);
  836. }
  837.  
  838.  
  839. /*
  840. ======================================================================
  841.  
  842. BLASTER / HYPERBLASTER
  843.  
  844. ======================================================================
  845. */
  846.  
  847. void Blaster_Fire (edict_t *ent, vec3_t g_offset, int damage, qboolean hyper, int effect)
  848. {
  849.     vec3_t    forward, right;
  850.     vec3_t    start;
  851.     vec3_t    offset;
  852.  
  853.     if (is_quad)
  854.         damage *= 4;
  855.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  856.     VectorSet(offset, 24, 8, ent->viewheight-8);
  857.     VectorAdd (offset, g_offset, offset);
  858.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  859.  
  860.     VectorScale (forward, -2, ent->client->kick_origin);
  861.     ent->client->kick_angles[0] = -1;
  862.  
  863.     fire_blaster (ent, start, forward, damage, 1000, effect, hyper);
  864.  
  865.     // send muzzle flash
  866.     gi.WriteByte (svc_muzzleflash);
  867.     gi.WriteShort (ent-g_edicts);
  868.     if (hyper)
  869.         gi.WriteByte (MZ_HYPERBLASTER | is_silenced);
  870.     else
  871.         gi.WriteByte (MZ_BLASTER | is_silenced);
  872.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  873.  
  874.     PlayerNoise(ent, start, PNOISE_WEAPON);
  875. }
  876.  
  877.  
  878. void Weapon_Blaster_Fire (edict_t *ent)
  879. {
  880.     int        damage;
  881.  
  882.     if (deathmatch->value)
  883.         damage = 15;
  884.     else
  885.         damage = 10;
  886.     Blaster_Fire (ent, vec3_origin, damage, false, EF_BLASTER);
  887.     ent->client->ps.gunframe++;
  888. }
  889.  
  890. void Weapon_Blaster (edict_t *ent)
  891. {
  892.     static int    pause_frames[]    = {19, 32, 0};
  893.     static int    fire_frames[]    = {5, 0};
  894.  
  895.     Weapon_Generic (ent, 4, 8, 52, 55, pause_frames, fire_frames, Weapon_Blaster_Fire);
  896. }
  897.  
  898.  
  899. void Weapon_HyperBlaster_Fire (edict_t *ent)
  900. {
  901.     float    rotation;
  902.     vec3_t    offset;
  903.     int        effect;
  904.     int        damage;
  905.  
  906.     ent->client->weapon_sound = gi.soundindex("weapons/hyprbl1a.wav");
  907.  
  908.     if (!(ent->client->buttons & BUTTON_ATTACK))
  909.     {
  910.         ent->client->ps.gunframe++;
  911.     }
  912.     else
  913.     {
  914.         if (! ent->client->pers.inventory[ent->client->ammo_index] )
  915.         {
  916.             if (level.time >= ent->pain_debounce_time)
  917.             {
  918.                 gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  919.                 ent->pain_debounce_time = level.time + 1;
  920.             }
  921.             NoAmmoWeaponChange (ent);
  922.         }
  923.         else
  924.         {
  925.             rotation = (ent->client->ps.gunframe - 5) * 2*M_PI/6;
  926.             offset[0] = -4 * sin(rotation);
  927.             offset[1] = 0;
  928.             offset[2] = 4 * cos(rotation);
  929.  
  930.             if ((ent->client->ps.gunframe == 6) || (ent->client->ps.gunframe == 9))
  931.                 effect = EF_HYPERBLASTER;
  932.             else
  933.                 effect = 0;
  934.             if (deathmatch->value)
  935.                 damage = 15;
  936.             else
  937.                 damage = 20;
  938.             Blaster_Fire (ent, offset, damage, true, effect);
  939.             if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  940.                 ent->client->pers.inventory[ent->client->ammo_index]--;
  941.  
  942.             ent->client->anim_priority = ANIM_ATTACK;
  943.             if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  944.             {
  945.                 ent->s.frame = FRAME_crattak1 - 1;
  946.                 ent->client->anim_end = FRAME_crattak9;
  947.             }
  948.             else
  949.             {
  950.                 ent->s.frame = FRAME_attack1 - 1;
  951.                 ent->client->anim_end = FRAME_attack8;
  952.             }
  953.         }
  954.  
  955.         ent->client->ps.gunframe++;
  956.         if (ent->client->ps.gunframe == 12 && ent->client->pers.inventory[ent->client->ammo_index])
  957.             ent->client->ps.gunframe = 6;
  958.     }
  959.  
  960.     if (ent->client->ps.gunframe == 12)
  961.     {
  962.         gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
  963.         ent->client->weapon_sound = 0;
  964.     }
  965.  
  966. }
  967.  
  968. void Weapon_HyperBlaster (edict_t *ent)
  969. {
  970.     static int    pause_frames[]    = {0};
  971.     static int    fire_frames[]    = {6, 7, 8, 9, 10, 11, 0};
  972.  
  973.     Weapon_Generic (ent, 5, 20, 49, 53, pause_frames, fire_frames, Weapon_HyperBlaster_Fire);
  974. }
  975.  
  976. /*
  977. ======================================================================
  978.  
  979. MACHINEGUN / CHAINGUN
  980.  
  981. ======================================================================
  982. */
  983.  
  984. void Machinegun_Fire (edict_t *ent)
  985. {
  986.     int    i;
  987.     vec3_t        start;
  988.     vec3_t        forward, right;
  989.     vec3_t        angles;
  990.     int            damage = 8;
  991.     int            kick = 2;
  992.     vec3_t        offset;
  993.  
  994.     if (!(ent->client->buttons & BUTTON_ATTACK))
  995.     {
  996.         ent->client->machinegun_shots = 0;
  997.         ent->client->ps.gunframe++;
  998.         return;
  999.     }
  1000.  
  1001.     if (ent->client->ps.gunframe == 5)
  1002.         ent->client->ps.gunframe = 4;
  1003.     else
  1004.         ent->client->ps.gunframe = 5;
  1005.  
  1006.     if (ent->client->pers.inventory[ent->client->ammo_index] < 1)
  1007.     {
  1008.         ent->client->ps.gunframe = 6;
  1009.         if (level.time >= ent->pain_debounce_time)
  1010.         {
  1011.             gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  1012.             ent->pain_debounce_time = level.time + 1;
  1013.         }
  1014.         NoAmmoWeaponChange (ent);
  1015.         return;
  1016.     }
  1017.  
  1018.     if (is_quad)
  1019.     {
  1020.         damage *= 4;
  1021.         kick *= 4;
  1022.     }
  1023.  
  1024.     for (i=1 ; i<3 ; i++)
  1025.     {
  1026.         ent->client->kick_origin[i] = crandom() * 0.35;
  1027.         ent->client->kick_angles[i] = crandom() * 0.7;
  1028.     }
  1029.     ent->client->kick_origin[0] = crandom() * 0.35;
  1030.     ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
  1031.  
  1032.     // raise the gun as it is firing
  1033.     if (!deathmatch->value)
  1034.     {
  1035.         ent->client->machinegun_shots++;
  1036.         if (ent->client->machinegun_shots > 9)
  1037.             ent->client->machinegun_shots = 9;
  1038.     }
  1039.  
  1040.     // get start / end positions
  1041.     VectorAdd (ent->client->v_angle, ent->client->kick_angles, angles);
  1042.     AngleVectors (angles, forward, right, NULL);
  1043.     VectorSet(offset, 0, 8, ent->viewheight-8);
  1044.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1045.     fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
  1046.  
  1047.     gi.WriteByte (svc_muzzleflash);
  1048.     gi.WriteShort (ent-g_edicts);
  1049.     gi.WriteByte (MZ_MACHINEGUN | is_silenced);
  1050.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1051.  
  1052.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1053.  
  1054.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1055.         ent->client->pers.inventory[ent->client->ammo_index]--;
  1056.  
  1057.     ent->client->anim_priority = ANIM_ATTACK;
  1058.     if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  1059.     {
  1060.         ent->s.frame = FRAME_crattak1 - (int) (random()+0.25);
  1061.         ent->client->anim_end = FRAME_crattak9;
  1062.     }
  1063.     else
  1064.     {
  1065.         ent->s.frame = FRAME_attack1 - (int) (random()+0.25);
  1066.         ent->client->anim_end = FRAME_attack8;
  1067.     }
  1068. }
  1069.  
  1070. void Weapon_Machinegun (edict_t *ent)
  1071. {
  1072.     static int    pause_frames[]    = {23, 45, 0};
  1073.     static int    fire_frames[]    = {4, 5, 0};
  1074.  
  1075.     Weapon_Generic (ent, 3, 5, 45, 49, pause_frames, fire_frames, Machinegun_Fire);
  1076. }
  1077.  
  1078. void Chaingun_Fire (edict_t *ent)
  1079. {
  1080.     int            i;
  1081.     int            shots;
  1082.     vec3_t        start;
  1083.     vec3_t        forward, right, up;
  1084.     float        r, u;
  1085.     vec3_t        offset;
  1086.     int            damage;
  1087.     int            kick = 2;
  1088.  
  1089.     if (deathmatch->value)
  1090.         damage = 6;
  1091.     else
  1092.         damage = 8;
  1093.  
  1094.     if (ent->client->ps.gunframe == 5)
  1095.         gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnu1a.wav"), 1, ATTN_IDLE, 0);
  1096.  
  1097.     if ((ent->client->ps.gunframe == 14) && !(ent->client->buttons & BUTTON_ATTACK))
  1098.     {
  1099.         ent->client->ps.gunframe = 32;
  1100.         ent->client->weapon_sound = 0;
  1101.         return;
  1102.     }
  1103.     else if ((ent->client->ps.gunframe == 21) && (ent->client->buttons & BUTTON_ATTACK)
  1104.         && ent->client->pers.inventory[ent->client->ammo_index])
  1105.     {
  1106.         ent->client->ps.gunframe = 15;
  1107.     }
  1108.     else
  1109.     {
  1110.         ent->client->ps.gunframe++;
  1111.     }
  1112.  
  1113.     if (ent->client->ps.gunframe == 22)
  1114.     {
  1115.         ent->client->weapon_sound = 0;
  1116.         gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/chngnd1a.wav"), 1, ATTN_IDLE, 0);
  1117.     }
  1118.     else
  1119.     {
  1120.         ent->client->weapon_sound = gi.soundindex("weapons/chngnl1a.wav");
  1121.     }
  1122.  
  1123.     ent->client->anim_priority = ANIM_ATTACK;
  1124.     if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  1125.     {
  1126.         ent->s.frame = FRAME_crattak1 - (ent->client->ps.gunframe & 1);
  1127.         ent->client->anim_end = FRAME_crattak9;
  1128.     }
  1129.     else
  1130.     {
  1131.         ent->s.frame = FRAME_attack1 - (ent->client->ps.gunframe & 1);
  1132.         ent->client->anim_end = FRAME_attack8;
  1133.     }
  1134.  
  1135.     if (ent->client->ps.gunframe <= 9)
  1136.         shots = 1;
  1137.     else if (ent->client->ps.gunframe <= 14)
  1138.     {
  1139.         if (ent->client->buttons & BUTTON_ATTACK)
  1140.             shots = 2;
  1141.         else
  1142.             shots = 1;
  1143.     }
  1144.     else
  1145.         shots = 3;
  1146.  
  1147.     if (ent->client->pers.inventory[ent->client->ammo_index] < shots)
  1148.         shots = ent->client->pers.inventory[ent->client->ammo_index];
  1149.  
  1150.     if (!shots)
  1151.     {
  1152.         if (level.time >= ent->pain_debounce_time)
  1153.         {
  1154.             gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/noammo.wav"), 1, ATTN_NORM, 0);
  1155.             ent->pain_debounce_time = level.time + 1;
  1156.         }
  1157.         NoAmmoWeaponChange (ent);
  1158.         return;
  1159.     }
  1160.  
  1161.     if (is_quad)
  1162.     {
  1163.         damage *= 4;
  1164.         kick *= 4;
  1165.     }
  1166.  
  1167.     for (i=0 ; i<3 ; i++)
  1168.     {
  1169.         ent->client->kick_origin[i] = crandom() * 0.35;
  1170.         ent->client->kick_angles[i] = crandom() * 0.7;
  1171.     }
  1172.  
  1173.     for (i=0 ; i<shots ; i++)
  1174.     {
  1175.         // get start / end positions
  1176.         AngleVectors (ent->client->v_angle, forward, right, up);
  1177.         r = 7 + crandom()*4;
  1178.         u = crandom()*4;
  1179.         VectorSet(offset, 0, r, u + ent->viewheight-8);
  1180.         P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1181.  
  1182.         fire_bullet (ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
  1183.     }
  1184.  
  1185.     // send muzzle flash
  1186.     gi.WriteByte (svc_muzzleflash);
  1187.     gi.WriteShort (ent-g_edicts);
  1188.     gi.WriteByte ((MZ_CHAINGUN1 + shots - 1) | is_silenced);
  1189.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1190.  
  1191.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1192.  
  1193.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1194.         ent->client->pers.inventory[ent->client->ammo_index] -= shots;
  1195. }
  1196.  
  1197.  
  1198. void Weapon_Chaingun (edict_t *ent)
  1199. {
  1200.     static int    pause_frames[]    = {38, 43, 51, 61, 0};
  1201.     static int    fire_frames[]    = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0};
  1202.  
  1203.     Weapon_Generic (ent, 4, 31, 61, 64, pause_frames, fire_frames, Chaingun_Fire);
  1204. }
  1205.  
  1206.  
  1207. /*
  1208. ======================================================================
  1209.  
  1210. SHOTGUN / SUPERSHOTGUN
  1211.  
  1212. ======================================================================
  1213. */
  1214.  
  1215. void weapon_shotgun_fire (edict_t *ent)
  1216. {
  1217.     vec3_t        start;
  1218.     vec3_t        forward, right;
  1219.     vec3_t        offset;
  1220.     int            damage = 4;
  1221.     int            kick = 8;
  1222.  
  1223.     if (ent->client->ps.gunframe == 9)
  1224.     {
  1225.         ent->client->ps.gunframe++;
  1226.         return;
  1227.     }
  1228.  
  1229.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1230.  
  1231.     VectorScale (forward, -2, ent->client->kick_origin);
  1232.     ent->client->kick_angles[0] = -2;
  1233.  
  1234.     VectorSet(offset, 0, 8,  ent->viewheight-8);
  1235.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1236.  
  1237.     if (is_quad)
  1238.     {
  1239.         damage *= 4;
  1240.         kick *= 4;
  1241.     }
  1242.  
  1243.     if (deathmatch->value)
  1244.         fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_DEATHMATCH_SHOTGUN_COUNT, MOD_SHOTGUN);
  1245.     else
  1246.         fire_shotgun (ent, start, forward, damage, kick, 500, 500, DEFAULT_SHOTGUN_COUNT, MOD_SHOTGUN);
  1247.  
  1248.     // send muzzle flash
  1249.     gi.WriteByte (svc_muzzleflash);
  1250.     gi.WriteShort (ent-g_edicts);
  1251.     gi.WriteByte (MZ_SHOTGUN | is_silenced);
  1252.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1253.  
  1254.     ent->client->ps.gunframe++;
  1255.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1256.  
  1257.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1258.         ent->client->pers.inventory[ent->client->ammo_index]--;
  1259. }
  1260.  
  1261. void Weapon_Shotgun (edict_t *ent)
  1262. {
  1263.     static int    pause_frames[]    = {22, 28, 34, 0};
  1264.     static int    fire_frames[]    = {8, 9, 0};
  1265.  
  1266.     Weapon_Generic (ent, 7, 18, 36, 39, pause_frames, fire_frames, weapon_shotgun_fire);
  1267. }
  1268.  
  1269.  
  1270. void weapon_supershotgun_fire (edict_t *ent)
  1271. {
  1272.     vec3_t        start;
  1273.     vec3_t        forward, right;
  1274.     vec3_t        offset;
  1275.     vec3_t        v;
  1276.     int            damage = 6;
  1277.     int            kick = 12;
  1278.  
  1279.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1280.  
  1281.     VectorScale (forward, -2, ent->client->kick_origin);
  1282.     ent->client->kick_angles[0] = -2;
  1283.  
  1284.     VectorSet(offset, 0, 8,  ent->viewheight-8);
  1285.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1286.  
  1287.     if (is_quad)
  1288.     {
  1289.         damage *= 4;
  1290.         kick *= 4;
  1291.     }
  1292.  
  1293.     v[PITCH] = ent->client->v_angle[PITCH];
  1294.     v[YAW]   = ent->client->v_angle[YAW] - 5;
  1295.     v[ROLL]  = ent->client->v_angle[ROLL];
  1296.     AngleVectors (v, forward, NULL, NULL);
  1297.     fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
  1298.     v[YAW]   = ent->client->v_angle[YAW] + 5;
  1299.     AngleVectors (v, forward, NULL, NULL);
  1300.     fire_shotgun (ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT/2, MOD_SSHOTGUN);
  1301.  
  1302.     // send muzzle flash
  1303.     gi.WriteByte (svc_muzzleflash);
  1304.     gi.WriteShort (ent-g_edicts);
  1305.     gi.WriteByte (MZ_SSHOTGUN | is_silenced);
  1306.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1307.  
  1308.     ent->client->ps.gunframe++;
  1309.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1310.  
  1311.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1312.         ent->client->pers.inventory[ent->client->ammo_index] -= 2;
  1313. }
  1314.  
  1315. void Weapon_SuperShotgun (edict_t *ent)
  1316. {
  1317.     static int    pause_frames[]    = {29, 42, 57, 0};
  1318.     static int    fire_frames[]    = {7, 0};
  1319.  
  1320.     Weapon_Generic (ent, 6, 17, 57, 61, pause_frames, fire_frames, weapon_supershotgun_fire);
  1321. }
  1322.  
  1323.  
  1324.  
  1325. /*
  1326. ======================================================================
  1327.  
  1328. RAILGUN
  1329.  
  1330. ======================================================================
  1331. */
  1332.  
  1333. void weapon_railgun_fire (edict_t *ent)
  1334. {
  1335.     vec3_t        start;
  1336.     vec3_t        forward, right;
  1337.     vec3_t        offset;
  1338.     int            damage;
  1339.     int            kick;
  1340.  
  1341.     if (deathmatch->value)
  1342.     {    // normal damage is too extreme in dm
  1343.         damage = 100;
  1344.         kick = 200;
  1345.     }
  1346.     else
  1347.     {
  1348.         damage = 150;
  1349.         kick = 250;
  1350.     }
  1351.  
  1352.     if (is_quad)
  1353.     {
  1354.         damage *= 4;
  1355.         kick *= 4;
  1356.     }
  1357.  
  1358.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1359.  
  1360.     VectorScale (forward, -3, ent->client->kick_origin);
  1361.     ent->client->kick_angles[0] = -3;
  1362.  
  1363.     VectorSet(offset, 0, 7,  ent->viewheight-8);
  1364.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1365.     fire_rail (ent, start, forward, damage, kick);
  1366.  
  1367.     // send muzzle flash
  1368.     gi.WriteByte (svc_muzzleflash);
  1369.     gi.WriteShort (ent-g_edicts);
  1370.     gi.WriteByte (MZ_RAILGUN | is_silenced);
  1371.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1372.  
  1373.     ent->client->ps.gunframe++;
  1374.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1375.  
  1376.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1377.         ent->client->pers.inventory[ent->client->ammo_index]--;
  1378. }
  1379.  
  1380.  
  1381. void Weapon_Railgun (edict_t *ent)
  1382. {
  1383.     static int    pause_frames[]    = {56, 0};
  1384.     static int    fire_frames[]    = {4, 0};
  1385.  
  1386.     Weapon_Generic (ent, 3, 18, 56, 61, pause_frames, fire_frames, weapon_railgun_fire);
  1387. }
  1388.  
  1389.  
  1390. /*
  1391. ======================================================================
  1392.  
  1393. BFG10K
  1394.  
  1395. ======================================================================
  1396. */
  1397.  
  1398. void weapon_bfg_fire (edict_t *ent)
  1399. {
  1400.     vec3_t    offset, start;
  1401.     vec3_t    forward, right;
  1402.     int        damage;
  1403.     float    damage_radius = 1000;
  1404.  
  1405.     if (deathmatch->value)
  1406.         damage = 200;
  1407.     else
  1408.         damage = 500;
  1409.  
  1410.     if (ent->client->ps.gunframe == 9)
  1411.     {
  1412.         // send muzzle flash
  1413.         gi.WriteByte (svc_muzzleflash);
  1414.         gi.WriteShort (ent-g_edicts);
  1415.         gi.WriteByte (MZ_BFG | is_silenced);
  1416.         gi.multicast (ent->s.origin, MULTICAST_PVS);
  1417.  
  1418.         ent->client->ps.gunframe++;
  1419.  
  1420.         PlayerNoise(ent, start, PNOISE_WEAPON);
  1421.         return;
  1422.     }
  1423.  
  1424.     // cells can go down during windup (from power armor hits), so
  1425.     // check again and abort firing if we don't have enough now
  1426.     if (ent->client->pers.inventory[ent->client->ammo_index] < 50)
  1427.     {
  1428.         ent->client->ps.gunframe++;
  1429.         return;
  1430.     }
  1431.  
  1432.     if (is_quad)
  1433.         damage *= 4;
  1434.  
  1435.     AngleVectors (ent->client->v_angle, forward, right, NULL);
  1436.  
  1437.     VectorScale (forward, -2, ent->client->kick_origin);
  1438.  
  1439.     // make a big pitch kick with an inverse fall
  1440.     ent->client->v_dmg_pitch = -40;
  1441.     ent->client->v_dmg_roll = crandom()*8;
  1442.     ent->client->v_dmg_time = level.time + DAMAGE_TIME;
  1443.  
  1444.     VectorSet(offset, 8, 8, ent->viewheight-8);
  1445.     P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start);
  1446.     fire_bfg (ent, start, forward, damage, 400, damage_radius);
  1447.  
  1448.     ent->client->ps.gunframe++;
  1449.  
  1450.     PlayerNoise(ent, start, PNOISE_WEAPON);
  1451.  
  1452.     if (! ( (int)dmflags->value & DF_INFINITE_AMMO ) )
  1453.         ent->client->pers.inventory[ent->client->ammo_index] -= 50;
  1454. }
  1455.  
  1456. void Weapon_BFG (edict_t *ent)
  1457. {
  1458.     static int    pause_frames[]    = {39, 45, 50, 55, 0};
  1459.     static int    fire_frames[]    = {9, 17, 0};
  1460.  
  1461.     Weapon_Generic (ent, 8, 32, 55, 58, pause_frames, fire_frames, weapon_bfg_fire);
  1462. }
  1463.  
  1464.  
  1465. //======================================================================
  1466.